package com.gitee.huanminabc.utils_tools.fast_cache;

import com.gitee.huanminabc.jcommon.multithreading.SleepTools;
import com.gitee.huanminabc.jcommon.multithreading.SimpleLockByTimeIntervalKey;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.lang.ref.SoftReference;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

@Slf4j
@Getter
public abstract class AbstractCache<V> implements Cache<String, V> {
    private static final long serialVersionUID = 1L;

    //同key锁
    protected SimpleLockByTimeIntervalKey<String> lockKey = new SimpleLockByTimeIntervalKey<>((key) -> key.hashCode() & 0x7FFFFFFF);

    //使用软引用，防止内存溢出
    @Setter
    protected Map<String, SoftReference<CacheObj<String, V>>> cacheMap;

    public AbstractCache(int capacity) {
        this(capacity, -1);
    }

    protected AbstractCache(int capacity, int timeout) {
        this.cacheMap = new ConcurrentHashMap<>(capacity);
        this.capacity = capacity;
        this.timeout = timeout;
        init();
    }

    private void init() {
        //启动一个线程持续清理过期缓存
        Thread thread = new Thread(() -> {
            while (true) {
                SleepTools.ms(1000 * 60 * 5); //5分钟清理一次
                prune();
            }
        });
        thread.setDaemon(true);
        thread.start();
    }

    ;
    /**
     * 返回缓存容量
     */
    protected int capacity;
    /**
     * 缓存失效时长， {@code -1} 表示无限制，单位毫秒
     */
    protected long timeout;


    //容量>100%
    protected boolean isFull() {
        return cacheMap.size() >= capacity;
    }

    //容量>95%
    protected boolean isNearlyFull() {
        return cacheMap.size() >= (capacity * 0.95);
    }

    //容量<80%
    protected boolean isHalfFull() {
        return cacheMap.size() <= (capacity * 0.80);
    }


    //丢弃并发的key 保证并发时候同key在 500ms内只执行一次 其他的丢弃 ,避免重复执行,影响性能
    //这个操作的目的就是,key加锁,可以让同一个key在一段时间内只执行一次,其他的丢弃
    public V discard(String key, int timeInterval, Supplier<V> function) {
        return lockKey.discard(key, timeInterval,function);
    }

    //默认500ms
    public V discard(String key,Supplier<V> function) {
        return discard(key, 500, function);
    }
    //默认500ms 不返回值
    public void discard(String key,Runnable consumer) {
        lockKey.discard(key, 500, consumer);
    }

    //添加缓存
    public boolean put(String key, V value) {
        return putInside(key, value) != null;
    }

    protected abstract CacheObj<String, V> putInside(String key, V value);

    public boolean put(String key, V value, long timeout) {
        return putInside(key, value, timeout) != null;
    }

    protected abstract CacheObj<String, V> putInside(String key, V value, long timeout);

    //获取缓存
    public V get(String key) {
        return getInside(key);
    }

    protected abstract V getInside(String key);


    //删除缓存
    public V remove(String key) {
        return removeInside(key);
    }

    protected abstract V removeInside(String key);

    //清空全部缓存
    public void clear() {
        clearInside();
    }

    protected abstract void clearInside();

    //允许手动强制gc缓存
    public void pruneCache() {
        prune();
    }

    protected abstract void prune();


}
